import { Injectable } from '@angular/core';
import { Graph, Node } from "@antv/x6";
import { CellType } from '../enums';
import { ScenarioConfig, PiplineConifg, SiteNodeConfig, SrmConfig, CellConfig } from '../models';

const cornerRadio = { rx: 2, ry: 2 };
@Injectable()
export class ScenarioMetaService {

  constructor() { }

  loadScenario(graph: Graph, scenario: ScenarioConfig) {
    graph.clearCells();
    scenario.Lines?.forEach(line => {
      const meta = this._getPiplineMeta(line);
      const lineNode = graph.addNode(meta);
      line.Sites.forEach(site => {
        const siteMeta = this._getSiteNodeMeta(site);
        const siteNode = graph.addNode(siteMeta);
        lineNode.addChild(siteNode);
      });
    });
    scenario.Srms?.forEach(srm => {
      const meta = this._getSrmMeta(srm);
      graph.addNode(meta);
    });
  }

  protected getMetas(scenario: ScenarioConfig): Node.Metadata[] {
    const result: Node.Metadata[] = [];
    if (scenario.Lines?.length) {
      scenario.Lines!.forEach(line => {
        result.push(this._getPiplineMeta(line));
        this._getSiteNodeMetas(line);
      });
    }
    return [];
  }
  protected _getPiplineMeta(cfg: PiplineConifg): Node.Metadata {
    const meta = this.getMetaFromType("Pipline");
    return {
      ...meta,
      id: cfg.Id,
      width: cfg.Width,
      height: cfg.Height,
      x: cfg.X,
      y: cfg.Y,
      label: cfg.Name,
      data: {
        // ...meta.data,
        title: cfg.Name,
        parent: true,
        category: "Pipline",
        plc: { ...cfg.Plc },
      },
    };
  }
  protected _getSiteNodeMetas(cfg: PiplineConifg): Node.Metadata[] {
    return cfg.Sites?.map(site => {
      return this._getSiteNodeMeta(site);
    });
  }

  protected _getSiteNodeMeta(item: SiteNodeConfig): Node.Metadata {
    const meta = this.getMetaFromType("Site");
    return {
      ...meta,
      id: item.Id,
      width: item.Width,
      height: item.Height,
      x: item.X,
      y: item.Y,
      label: item.Name,
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          ...cornerRadio
        },
      },
      data: {
        category: "Site",
        title: item.Name,
        fields: [...item.Fields ?? []]
      },
      zIndex: 2,
    };
  }

  protected _getSrmMeta(item: SrmConfig): Node.Metadata {
    const meta = this.getMetaFromType("Srm");
    return {
      ...meta,
      id: item.Id,
      width: item.Width,
      height: item.Height,
      x: item.X,
      y: item.Y,
      label: item.Name,
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          ...cornerRadio
        },
      },
      data: {
        category: "Srm",
        title: item.Name,
        plc: { ...item.Plc },
        fields: [...item.Fields ?? []]
      },
      zIndex: 2,
    };
  }

  getMetaFromType(type: string): Node.Metadata {
    switch (type) {
      case "Site":
        return {
          width: 100,
          height: 40,
          shape: 'rect',
          label: 'Site',
          attrs: {
            body: {
              stroke: '#8f8f8f',
              strokeWidth: 1,
              fill: '#fff',
              ...cornerRadio
            },
          },
          data: {
            category: "Site",
            title: "Site",
            fields: [],
          },
          zIndex: 2,
        };
      case "Srm":
        return {
          width: 300,
          height: 50,
          shape: 'rect',
          label: 'Srm',
          attrs: {
            body: {
              stroke: '#8f8f8f',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
          data: {
            category: "Srm",
            title: "Srm",
          },
          zIndex: 2,
        };
      case "Pipline":
        return {
          width: 500,
          height: 100,
          shape: "rect",
          label: 'Pipline',
          attrs: {
            body: {
              stroke: '#8f8f8f',
              strokeWidth: 1,
              fill: '#ccc',
              ...cornerRadio
            },
            text: {
              fontSize: 36,
            }
          },
          data: {
            category: "Pipline",
            title: "Pipline",
            parent: true
          },
          zIndex: 1,
        };
    }
    return {};
  }

  getScenario(nodes: Node[], scenario?: ScenarioConfig) {
    return {
      ...scenario,
      ...this._nodesToScenario(nodes),
    };
  }

  protected _nodesToScenario(nodes: Node<Node.Properties>[]): ScenarioConfig {
    const lines = nodes.filter(node => node.data.category == "Pipline");
    const lineConfigs = lines.map<PiplineConifg>((item, i) => {
      const sites = nodes.filter(n => n.parent?.id == item.id).map<SiteNodeConfig>(n => {
        const { x, y } = n.position();
        const { width, height } = n.size();
        const { fields } = n.data;
        return {
          Id: n.id,
          Type: CellType.Site,
          Name: n.data.title,
          X: Math.round(x),
          Y: Math.round(y),
          Width: width,
          Height: height,
          ParentId: item.id,
          Fields: fields ?? [],
        };
      });
      const { x, y } = item.position();
      const { width, height } = item.size();
      return {
        Id: item.id,
        Type: CellType.Pipline,
        X: Math.round(x),
        Y: Math.round(y),
        Name: item.data.title,
        Width: width,
        Height: height,
        Sites: sites,
        Plc: {
          ...item.data.plc
        }
      };
    });

    const srmConfigs = nodes.filter(node => node.data.category == "Srm").map<SrmConfig>(n => {
      const { x, y } = n.position();
      const { width, height } = n.size();
      return {
        Id: n.id,
        Type: CellType.Srm,
        Name: n.data.title,
        X: Math.round(x),
        Y: Math.round(y),
        Width: width,
        Height: height,
        Plc: { ...n.data.plc },
        Fields: [...n.data.fields ?? []]
      };
    });
    const config: ScenarioConfig = {
      Lines: [...lineConfigs],
      Srms: [...srmConfigs],
    };
    return config;
  }

  getCellConfig(node: Node): CellConfig | undefined {
    const { category } = node.data;
    const { x, y } = node.position();
    const { width, height } = node.size();
    switch (category) {
      case CellType.Pipline:
        {
          const item: PiplineConifg = {
            Id: node.id,
            Type: CellType.Pipline,
            X: Math.round(x),
            Y: Math.round(y),
            Name: node.data.title,
            Width: width,
            Height: height,
            Sites: [],
            Plc: {
              ...node.data.plc
            },
          };
          return item;
        }
        break;
      case CellType.Site:
        {
          const id = node.parent?.id;
          if (id) {
            const item: SiteNodeConfig = {
              Id: node.id,
              Type: CellType.Site,
              Name: node.data.title,
              X: Math.round(x),
              Y: Math.round(y),
              Width: width,
              Height: height,
              ParentId: id,
              Fields: [...node.data.fields ?? []],
            };
            return item;
          }
        }
        break;
      case CellType.Srm:
        {
          const item: SrmConfig = {
            Id: node.id,
            Type: CellType.Srm,
            Name: node.data.title,
            X: Math.round(x),
            Y: Math.round(y),
            Width: width,
            Height: height,
            Plc: { ...node.data.plc },
            Fields: [...node.data.fields ?? []]
          };
          return item;
        }
        break;
      default:
        break;
    }
    return undefined;
  }
}
